#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <iconv.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "syscore.h"
#include "apis.h"
#include "common.h" 
#include "3gcmn.h"
#include "smstask.h"
#include "modules.h"
#include "transform.h"

#define CLIENT_MAX  4
#define SMS_PASSWORD    "1635"
#define SESSION_TIMEOUT 600
const char *dongleLogFile = "/mnt/usr/log/3gdongle.log";
const char *LogLevelName[8] =
{
    "EMERGENCY",
    "ALERT",
    "CRITICAL",
    "ERROR",
    "WARNING",
    "NOTICE",
    "INFO",
    "DEBUG"
} ;
FILE *log;
int32_t dongleLogLevel = LOG_USE_GLOBAL_FILTER;
pthread_mutex_t mutexLog;
static int32_t lineNum = 0;
typedef char * ItemHandler(char *str);
char smsKey[16];
typedef struct {
    const char *id;
    const char *text;
    ItemHandler *handler;
}Item_t;

typedef enum {
    Auth_Init = 0,
    Auth_WaitPassword,
    Auth_Normal,
    Auth_Timeout
}AuthState_t;

typedef struct {
    SMS_MSG sms;
    int32_t Timeout;
    struct timeval stamp;
    AuthState_t Auth;
    uint32_t flag;
}Client_t;

static Client_t RemoteClients[CLIENT_MAX];

static char * ItemQueryAllCommand(char *str);
static char * ItemQueryDeviceStatus(char *str);
static char * ItemQuerySWVersion(char *str);
static char * ItemQueryIP(char *str);
static char * ItemQueryDiskStatus(char *str);
static char * ItemSetCommandReset(char *str);
static char * ItemSetCommandRecovery(char *str);
static char * ItemTesting(char *str);

Item_t MenuList[] = 
{
    {
        "000",
        "返回支持的的查询命令",
        ItemQueryAllCommand
    },
    {
        "001",
        "查询系统状态，包括主要模块状态",
        ItemQueryDeviceStatus
    },
    {
        "002",
        "查询软件版本",
        ItemQuerySWVersion
    },
    {
        "003",
        "查询WAN口IP地址",
        ItemQueryIP 
    },
    {
        "004",
        "查询硬盘空间",
        ItemQueryDiskStatus
    },
    {
        "005",
        "返回支持的设置命令",
        ItemQueryAllCommand
    },
    {
        "006",
        "重启系统",
        ItemSetCommandReset
    },
    {
        "007",
        "恢复出厂设置",
        ItemSetCommandRecovery
    },
    {
        "008",
        "复位3G dongle",
        ItemTesting
    }
};

static char ItemQueryTextBuffer[1024];
static int SystemResetFlag = 0;
static int SystemRecoveryFlag = 0;
void Send3gMsg_nopara(uint16_t dst_id, uint16_t cmd_code, uint16_t cmd_idx);



static char * ItemQueryAllCommand(char *str)
{
    int i;
    int count;
    int len;
    char *buf;

    buf = ItemQueryTextBuffer;
    len = sprintf(ItemQueryTextBuffer, "提示：\n");
    buf += len;

    count = sizeof(MenuList)/sizeof(MenuList[0]);

    for(i=0; i<count; i++)
    {
        len = sprintf(buf,"%s %s\n", MenuList[i].id, MenuList[i].text);
        buf += len;
    }

    return ItemQueryTextBuffer;
}

static char * ItemQueryDeviceStatus(char *str)
{
    sprintf(ItemQueryTextBuffer, "状态未知！\n");

    return ItemQueryTextBuffer;
}

static char * ItemQuerySWVersion(char *str)
{

    sprintf(ItemQueryTextBuffer, "版本未知！\n");

    return ItemQueryTextBuffer;
}

static char * ItemQueryIP(char *str)
{

    int sockfd = -1;
    struct sockaddr_in *addr;
    struct ifreq tmp;
    strcpy(tmp.ifr_name, "eth1");

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
       sprintf(ItemQueryTextBuffer, "WAN IP为:\n%s", "0.0.0.0");
       return ItemQueryTextBuffer;
  
    }
    if ((ioctl(sockfd, SIOCGIFADDR, &tmp)) < 0)
    {
       close(sockfd);
       sprintf(ItemQueryTextBuffer, "WAN IP为:\n%s", "0.0.0.0");
       sockfd = -1;
       return ItemQueryTextBuffer;
    }
    else
    {
        addr = (struct sockaddr_in *)&(tmp.ifr_addr);
        sprintf(ItemQueryTextBuffer, "WAN IP为:\n%s", (char *)inet_ntoa(addr->sin_addr));
        close(sockfd); 
        
    }

    return ItemQueryTextBuffer;
}

static char * ItemQueryDiskStatus(char *str)
{
    int ret;
    int fd;

    ret = system("df -h > /tmp/diskinfo");
    
    if(ret < 0)
    {
        sprintf(ItemQueryTextBuffer, "查询硬盘失败！\n");
    }
    else
    {
        fd = open("/tmp/diskinfo", O_RDONLY);
        if(fd < 0)
        {
            sprintf(ItemQueryTextBuffer, "查询硬盘失败！\n");
        }
        else
        {
            memset(ItemQueryTextBuffer, 0 , sizeof(ItemQueryTextBuffer));
            read(fd, ItemQueryTextBuffer, sizeof(ItemQueryTextBuffer));
            close(fd);
        }
    }

    return ItemQueryTextBuffer;
}

static char * ItemSetCommandReset(char *str)
{
    SystemResetFlag = 1;
    sprintf(ItemQueryTextBuffer, "系统正在重启...\n");
    Send3gMsg_nopara(MODULE_SYSTEM, CMD_CODE_SYS_REBOOT, 0);
    return ItemQueryTextBuffer;
}

static char * ItemSetCommandRecovery(char *str)
{
    SystemRecoveryFlag = 1;
    sprintf(ItemQueryTextBuffer, "系统正在还原...\n");

    return ItemQueryTextBuffer;
}

static char * ItemTesting(char *str)
{
    sprintf(ItemQueryTextBuffer, "Testing");

    return ItemQueryTextBuffer;
}

static int32_t FindMenuItems(SMS_MSG *smsMsg)
{
    int32_t item = -1;
    char text[1024];
    unsigned int i;

    if(smsMsg != NULL)
    {
        if(smsMsg->format == PARA_VALUE_3G_SMS_FORMAT_UNICODE)
        {
            /* normally Query number should not be unicode */
            memset(text, 0, sizeof(text));
            i = Utf16ToUtf8(smsMsg->text, smsMsg->smsLength, text, sizeof(text));

            if(i>0)
            {
               // printf("%s\n", text);
                for(i=0; i<(sizeof(MenuList)/sizeof(MenuList[0])); i++)
                {
                    if(!strcmp(text, MenuList[i].id))
                    {
                        break;
                    }
                }
                item = i;
            }
        }
        else if(smsMsg->format == PARA_VALUE_3G_SMS_FORMAT_ASCII)
        {
            //printf("%s\n", smsMsg->text);
            for(i=0; i<(sizeof(MenuList)/sizeof(MenuList[0])); i++)
            {
                if(!strcmp(smsMsg->text, MenuList[i].id))
                {
                    break;
                }
            }
            item = i;
        }
        else
        {
            DONGLE_LOG(LOG_WARNING, "format not supported!\n");
        }
    }

    if(item >= (int)(sizeof(MenuList)/sizeof(MenuList[0])))
    {
        item = -1; 
    }

    return item;
}

int32_t FindClient(char *id)
{
    int32_t index;

    for(index=0; index<(int32_t)(sizeof(RemoteClients)/sizeof(RemoteClients[0])); index++)
    {
        if(!strcmp(RemoteClients[index].sms.callerId, id))
        {
            break;
        }
    }
    return index;
}

int32_t FindFreeClient(void)
{
    int32_t index;

    for(index=0; index<(int32_t)(sizeof(RemoteClients)/sizeof(RemoteClients[0])); index++)
    {
        if(!strlen(RemoteClients[index].sms.callerId))
        {
            break;
        }
    }
    return index;    
}

int32_t ReleaseClient(int32_t index)
{
    if(index>=0 && index < (int32_t)(sizeof(RemoteClients)/sizeof(RemoteClients[0])))
    {
        memset(&RemoteClients[index], 0, sizeof(RemoteClients[0]));
    }

    return index;
}

#define  debug_dump_buffer(num, str)  {                                \
    if( (num) > 0 )                                                    \
    {                                                                  \
        int32_t pst = 0;                                               \
        printf("DUMP BIN(%d): ", num);                                 \
        for( ; pst < num - 1; ++pst )                                  \
            printf("0x%02X,", *((unsigned char*)str + pst));           \
        printf("0x%02X\n", *((unsigned char*)str + num - 1));          \
    }                                                                  \
}

int32_t rx_queue_id = 0;
int32_t tx_queue_id = 0;

FIFO_MSGQUEUE mgr2SmsMsgQueue;  /* mgr ---normal msgs--> sms */
FIFO_MSGQUEUE sms2MgrMsgQueue;  /* sms ---normal msgs--> mgr */

bool stop_3g_thread = false;
bool smsTaskEnabled = false;
bool smsMainEnabled = true;
uint16_t sim_state_dst_id = 0;
uint16_t sim_state_cmd_idx = 0;

#ifdef DONGLE_THREAD
MODREG mod3gInfo = { MODULE_SMS, false, false, 1000, NULL };
#endif

bool send_qmsg(char *msg, U16 length)
{
    int ret_value = msgsnd(tx_queue_id, msg, length, 0);  
    if( ret_value < 0 ) 
    {  
        DONGLE_LOG(LOG_WARNING, "msgsnd() msg failed mtype=%ld, length=%d, errno=%d[%s]\n", 
                *(long*)msg, length, errno, strerror(errno));  
        return false;  
    }
    return true;
}

void report3gHeartBeat(bool IsOk)
{
    U32 rc = PARA_VALUE_SYSMONITOR_MODULE_ERROR;
    if ( IsOk )
         rc = PARA_VALUE_SYSMONITOR_MODULE_OK;
        
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = MODULE_SYSMONITOR;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType =  CMD_EVENT;
    cmd->cmdCode = CMD_CODE_SYSMONITOR_HEARTBEAT;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);

    *(uint32_t*)ptr = PARA_TYPE_SYSMONITOR_MODULE_STATE;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = rc;
    cmd->cmdLength += sizeof(uint32_t) * 4;
    

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_WARNING, "can't report msg, mtype=%d length=%d \n", 
                   msg_header->msgType, msg_header->msgLength);
    }
}

void Send3gMsg_nopara(uint16_t dst_id, uint16_t cmd_code, uint16_t cmd_idx)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = dst_id;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_SET;
    cmd->cmdCode = cmd_code;
    cmd->cmdIndex = cmd_idx;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_ERR, "%s, can't report msg, mtype=%d length=%d \n", __func__, 
                msg_header->msgType, msg_header->msgLength);
    }




}

void report3gResult(uint16_t dst_id, uint16_t cmd_code, uint16_t cmd_idx, uint32_t result, uint32_t err_code)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = dst_id;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_SET_RESPONSE;
    cmd->cmdCode = cmd_code;
    cmd->cmdIndex = cmd_idx;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);

    if( PARA_VALUE_RESULT_FAILED == result )
    {
        *(uint32_t*)ptr = PARA_TYPE_RESULT;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = PARA_VALUE_RESULT_FAILED;
        ptr += sizeof(uint32_t) + sizeof(uint32_t);
        cmd->cmdLength += sizeof(uint32_t) * 4;

        *(uint32_t*)ptr = PARA_TYPE_ERROR_CODE;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = PARA_VALUE_ERROR_XG_OK + err_code;
        cmd->cmdLength += sizeof(uint32_t) *4 ;
    }
    else
    {
        *(uint32_t*)ptr = PARA_TYPE_RESULT;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = result;
        cmd->cmdLength += sizeof(uint32_t) * 4;
    }

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_ERR, "%s, can't report msg, mtype=%d length=%d \n", __func__, 
                msg_header->msgType, msg_header->msgLength);
    }
}

void reportSms(SMS_MSG *smsMsg)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = MODULE_SYSTEM;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_EVENT;
    cmd->cmdCode = CMD_CODE_SMS_REPORT;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;
    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);

    uint8_t *tlv_start = (uint8_t *)msg_payload;
    tlv_start += sizeof(CMDHEADER);

    int32_t tlvLength = 0;
    PARAM *tlv = (PARAM *)tlv_start;
    tlv->paraType = PARA_TYPE_3G_SMS_CALLER_ID;
    tlv->paraLength = strlen(smsMsg->callerId);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    memcpy(tlv->paraValue, smsMsg->callerId, tlv->paraLength);
    cmd->cmdLength += tlvLength;

/*    tlv = (PARAM *)(tlv_start + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_3G_SMS_LENGTH;
    tlv->paraLength = sizeof(int32_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *((int32_t *)tlv->paraValue) = smsMsg->smsLength;
    cmd->cmdLength += tlvLength;*/

    tlv = (PARAM *)(tlv_start + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_3G_SMS_FORMAT;
    tlv->paraLength = sizeof(int32_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(tlv_start + cmd->cmdLength + sizeof(PARAM)) = smsMsg->format;
    cmd->cmdLength += tlvLength;

    tlv = (PARAM *)(tlv_start + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_3G_SMS_TEXT;
    tlv->paraLength = smsMsg->smsLength;
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    memcpy(tlv->paraValue, smsMsg->text, tlv->paraLength);
    cmd->cmdLength += tlvLength;

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_ERR, "%s, can't report msg \n", __func__);
    }
}

void reportSimState(uint16_t dstId, uint16_t cmd_idx, SIM_STATE *simState)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = dstId;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_GET_RESPONSE;
    cmd->cmdCode = CMD_CODE_GET_SIM_STATE;
    cmd->cmdIndex = cmd_idx;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    unsigned char *ptr = (unsigned char *)msg_payload;
    ptr += sizeof(CMDHEADER);

    *(uint32_t*)ptr = PARA_TYPE_3G_SIM_STATE;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = simState->valid;
    ptr += sizeof(uint32_t);

    cmd->cmdLength = sizeof(uint32_t) * 3;

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_ERR, "%s, can't report msg \n", __func__);
    }
}
void reportSmsState(uint16_t dstId, uint16_t cmd_idx)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = dstId;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_GET_RESPONSE;
    cmd->cmdCode = CMD_CODE_GET_SMS_STATE;
    cmd->cmdIndex = cmd_idx;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    unsigned char *ptr = (unsigned char *)msg_payload;
    ptr += sizeof(CMDHEADER);

    *(uint32_t*)ptr = PARA_TYPE_3G_SMS_STATE;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = smsTaskEnabled;
    ptr += sizeof(uint32_t);

    cmd->cmdLength = sizeof(uint32_t) * 3;

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_ERR, "%s, can't report msg \n", __func__);
    }
}

void reportAlarm(SMS_ALARM *alarm)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = MODULE_INTF;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_EVENT;
    cmd->cmdCode = alarm->id;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    unsigned char *ptr = (unsigned char *)msg_payload;
    ptr += sizeof(CMDHEADER);

    *(int32_t*)ptr = PARA_TYPE_3G_ALARM_REASON;
    ptr += sizeof(int32_t);
    *(int32_t*)ptr = sizeof(int32_t);
    ptr += sizeof(int32_t);
    *(int32_t*)ptr = alarm->reason;
    ptr += sizeof(int32_t);

    cmd->cmdLength = sizeof(int32_t) * 3;

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_ERR, "%s, can't report alarm 0x%X \n", __func__, alarm->id);
    }
}

void tvl3gMsgHdlrQuarantine(PMSGHEADER header)
{
    int32_t len = header->msgLength, cmd_len = 0;
    unsigned char *ptr = ((unsigned char*)header) + sizeof(MSGHEADER);
    uint16_t srcId = header->srcID;

    if( MODULE_SMS != header->dstID )
    {
        DONGLE_LOG(LOG_ERR,"%s, received a wrong tlv msg id = %d \n", __func__, header->dstID);
        return;
    }

    if( MSG_TYPE_COMMAND == header->msgType )
    {
        len -= sizeof(MSGHEADER);
        while( len >= (int32_t)sizeof(CMDHEADER) )
        {
            /* processing one command */
            char calledList[AT_SMS_CALLED][16];
            int32_t calledNum = 0, i;
            SMS_MSG smsMsg;
            uint32_t tlvRecvFlag = 0;
            xg_ret_t ret = xg_ret_ok;
            bool report_result = true;

            PCMDHEADER cmd = (PCMDHEADER)ptr;

            ptr += sizeof(CMDHEADER);
            len -= sizeof(CMDHEADER);
            switch( cmd->cmdCode ) {
                case CMD_CODE_SYS_REBOOT:
                    if( ! smsTaskEnabled )
                    {
                        break;
                    }
                    stopSmsTask();
                    smsTaskEnabled = false;
                    //stop_3g_thread = true;
                    report_result = false;
                    break;
                case CMD_CODE_SMS_OFF:
                    if( ! smsTaskEnabled )
                    {
                        ret = xg_sms_off;
                        break;
                    }

                    stopSmsTask();
                    smsTaskEnabled = false;
                    break;
                case CMD_CODE_SMS_ON:
                    cmd_len = cmd->cmdLength;
                    while( cmd_len >= (int32_t)sizeof(PARAM) )
                    {
                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
                        switch( tlv->paraType ) {
                            case PARA_TYPE_3G_WORKMODE :
                                {  
                                   cmd_len -= tlvLength;
                            
                                   if (*(U32 *)tlv->paraValue == PARA_VALUE_WOKRING_TYPE_NORMAL )
                                   {
                                       SetcheckWanTrue();
                                       DONGLE_LOG(LOG_INFO, "workmode is %d so start check wan \n", *(U32 *)tlv->paraValue);
                                   }
                                }
                                break;
                            default:
                                ret = xg_err_param;
                                break;
                        }
                    }
                 
                    if( smsTaskEnabled )
                    {
                        ret = xg_sms_on;
                        break;
                    }

                    if( !initSmsTask() )
                    {
                        DONGLE_LOG(LOG_ERR, "can't create smstask thread \n");
                        ret = xg_ret_nok;
                        // @TODO, raise alarm.
                        break;
                    }

                    smsTaskEnabled = true;
                    break;

                case CMD_CODE_SMS_MAINT_ON:
                    smsMainEnabled = true;
                    break;
  
                case CMD_CODE_SMS_MAINT_OFF:
                    smsMainEnabled = false;
                    break;

                case CMD_CODE_SMS_KEY:
                    cmd_len = cmd->cmdLength;
                    while( cmd_len >= (int32_t)sizeof(PARAM) )
                    {
                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
                        switch( tlv->paraType ) {
                            case PARA_TYPE_3G_SMS_KEY:
                                memset(smsKey, 0, 16);
                                memcpy(smsKey, tlv->paraValue, tlv->paraLength);
                                DONGLE_LOG(LOG_INFO, "set smsKey is %s \n",  smsKey);
                                cmd_len -= tlvLength;
                                break;
                            default:
                                ret = xg_err_param;
                                break;
                        }
                    }                   
                     break;
#ifdef MODULE_TEST
                case CMD_CODE_SYSMONITOR_TEST_MODULE:
                    cmd_len = cmd->cmdLength;
                    while( cmd_len >= (int32_t)sizeof(PARAM) )
                    {
                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
                        switch( tlv->paraType ) {
                            case PARA_TYPE_SYSMONITOR_TEST:
                              {  cmd_len -= tlvLength;
                            
                                if (*(U32 *)tlv->paraValue == PARA_VALUE_SYSMONITOR_MAIN )
                                {
                                   DONGLE_LOG(LOG_WARNING, "----- test module 3gdongle ----- %04x\n", CMD_CODE_SYSMONITOR_TEST_MODULE);
                                   while(1)
                                   {

                                   }
                                   break;
                                }
                                else if (*(U32 *)tlv->paraValue == PARA_VALUE_SYSMONITOR_THREAD1 )
                                {

                                    setTestCheckWan();
                                }
                                else
                                {
                                    setTestSms();
                                }
                              }
                                break;
                            default:
                                ret = xg_err_param;
                                break;
                        }
                    }                   
                     break;
#endif

                case CMD_CODE_SEND_SMS:

                    cmd_len = cmd->cmdLength;
                    while( cmd_len >= (int32_t)sizeof(PARAM) )
                    {
                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
                        switch( tlv->paraType ) {
                            case PARA_TYPE_3G_SMS_CALLED_ID:
                                memset(calledList[calledNum], 0, 16);
                                memcpy(calledList[calledNum++], tlv->paraValue, tlv->paraLength);
                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 1;
                                break;
                            case PARA_TYPE_3G_SMS_LENGTH:
                                smsMsg.smsLength = *(int32_t*)(ptr + sizeof(PARAM));
                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                //tlvRecvFlag |= 8;
                                break;
                            case PARA_TYPE_3G_SMS_FORMAT:
                                smsMsg.format = *(int32_t*)(ptr + sizeof(PARAM));
                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 2;
                                break;
                            case PARA_TYPE_3G_SMS_TEXT:
                                smsMsg.smsLength = tlv->paraLength;
                                memcpy(smsMsg.text, tlv->paraValue, tlv->paraLength);
                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 4;
                                break;
                            default:
                                DONGLE_LOG(LOG_NOTICE, "%s, param type %d not supported \n", __func__, tlv->paraType);
                                break;
                        }
                    }
                    if( tlvRecvFlag != 0x7 )
                    {
                        DONGLE_LOG(LOG_NOTICE,"%s, param missing detected \n", __func__);
                        ret = xg_err_param;
                        break;
                    }
                    for( i = 0; i < calledNum; ++i )
                    {
                        smsMsg.header.msgId = MSG_ID_SMS;
                        memcpy(smsMsg.callerId, calledList[i], strlen(calledList[i]));
                        addMsgToFifoMsgQueue(&mgr2SmsMsgQueue, &smsMsg, sizeof(SMS_MSG));
                    }

                    break;
                case CMD_CODE_GET_SIM_STATE:
                    {
                        MSG_HEADER msghdr;
                        msghdr.msgId = MSG_ID_GET_SIM_STATE;
                        addMsgToFifoMsgQueue(&mgr2SmsMsgQueue, &msghdr, sizeof(MSG_HEADER));
                        sim_state_dst_id = srcId;
                        sim_state_cmd_idx = cmd->cmdIndex;
                        report3gResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_DOING, PARA_VALUE_ERROR_NO_ERROR);
                        report_result = false;
                    }
                    break;
                case CMD_CODE_GET_SMS_STATE:
                    {
                        reportSmsState(srcId, cmd->cmdIndex);
                        report_result = false;
                    }
                    break;
                default:
                    DONGLE_LOG(LOG_NOTICE, "%s, msg cmd %d not supported, len=%d \n", __func__, cmd->cmdCode, len);
                    ret = xg_not_supported;
                    break;
            }

            if( report_result )
            {
                if( xg_ret_ok == ret )
                {
                    report3gResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR);
                }
                else if ( ret != xg_not_supported )
                {
                    report3gResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_FAILED, ret);
                }
            }
            else
            {
                report_result = true;
            }

            ptr += cmd->cmdLength;
            len -= cmd->cmdLength;
        }
    }
    else if( MSG_TYPE_INTERNAL == header->msgType )
    {

    }
    else
    {
        DONGLE_LOG(LOG_NOTICE, "%s, msg type %d not supported \n", __func__, header->msgType);
    }
}

void tvl3gMsgHdlr(PMSGHEADER header)
{
    int32_t len = header->msgLength, cmd_len = 0;
    unsigned char *ptr = ((unsigned char*)header) + sizeof(MSGHEADER);
    uint16_t srcId = header->srcID;

    if( MODULE_SMS != header->dstID )
    {
        DONGLE_LOG(LOG_ERR,"%s, received a wrong tlv msg id = %d \n", __func__, header->dstID);
        return;
    }

    if( MSG_TYPE_COMMAND == header->msgType )
    {
        len -= sizeof(MSGHEADER);
        while( len >= (int32_t)sizeof(CMDHEADER) )
        {
            /* processing one command */
            bool report_result = true;

            PCMDHEADER cmd = (PCMDHEADER)ptr;

            ptr += sizeof(CMDHEADER);
            len -= sizeof(CMDHEADER);
            switch( cmd->cmdCode ) 
			{
                case CMD_CODE_SYS_REBOOT:
                    break;
                case CMD_CODE_SMS_OFF:
                    break;
                case CMD_CODE_SMS_ON:
                    cmd_len = cmd->cmdLength;
                    while( cmd_len >= (int32_t)sizeof(PARAM) )
                    {
                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
                        switch( tlv->paraType ) 
						{
                            case PARA_TYPE_3G_WORKMODE :
                                {  
                                   cmd_len -= tlvLength;
                            
                                   if (*(U32 *)tlv->paraValue == PARA_VALUE_WOKRING_TYPE_NORMAL )
                                   {
                                       DONGLE_LOG(LOG_INFO, "workmode is %d so start check wan \n", *(U32 *)tlv->paraValue);
                                   }
                                }
							
                                break;
                            default:
                                break;
                        }
                    }
                 
                    break;

                case CMD_CODE_SMS_MAINT_ON:
                    break;
  
                case CMD_CODE_SMS_MAINT_OFF:
                    break;

                case CMD_CODE_SMS_KEY:                  
                     break;
#ifdef MODULE_TEST
                case CMD_CODE_SYSMONITOR_TEST_MODULE:             
                     break;
#endif
                case CMD_CODE_SEND_SMS:
                    break;
                case CMD_CODE_GET_SIM_STATE:
                    break;
                case CMD_CODE_GET_SMS_STATE:
                    break;
                default:
                    report_result = false; 
                    DONGLE_LOG(LOG_NOTICE, "%s, msg cmd %d not supported, len=%d \n", __func__, cmd->cmdCode, len);
                    break;
            }

            if(cmd->cmdType == CMD_EVENT)
            {
                continue;
            }

            if( report_result )
            {
                report3gResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR);
            }
            else
            {
				//report3gResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_FAILED, xg_not_supported);
            }

            ptr += cmd->cmdLength;
            len -= cmd->cmdLength;
        }
    }
    else if( MSG_TYPE_INTERNAL == header->msgType )
    {
        //no need to handle;
    }
    else
    {
        DONGLE_LOG(LOG_NOTICE, "%s, msg type %d not supported \n", __func__, header->msgType);
    }
}

void dongle_msgqueue_init(void)
{
    key_t key = ftok("/tmp", MSGQ_FTOK_ID);
    if( key == (key_t) - 1 ) 
    {
        DONGLE_LOG(LOG_EMERG, "ftok(%d) failed, %s\n", MSGQ_FTOK_ID, strerror(errno));
        exit(EXIT_FAILURE);
    }
    rx_queue_id = msgget(key, IPC_CREAT);
    DONGLE_LOG(LOG_INFO,"%s, rx_queue_id = %d \n", __func__, rx_queue_id);

    key = ftok("/tmp", MSGQ_FTOK_ID ^ 0xff);
    if( key == (key_t) - 1 ) 
    {
        DONGLE_LOG(LOG_EMERG, "ftok(%d) failed, %s\n", MSGQ_FTOK_ID ^ 0xff, strerror(errno));
        if( tx_queue_id != 0 )
        {   
            msgctl(rx_queue_id, IPC_RMID, NULL);
            rx_queue_id = 0;   
        }
        exit(EXIT_FAILURE);
    }
    tx_queue_id = msgget(key, IPC_CREAT);
    DONGLE_LOG(LOG_INFO, "%s, tx_queue_id = %d \n", __func__, tx_queue_id);
}

static void dongle_send_msg(char *text, int len, SMS_MSG *smsMsg)
{
    int item;
    if(len > AT_SMS_MAXLEN)
    {
        for(item=0; item < (len/AT_SMS_MAXLEN); item++);
        {
            smsMsg->smsLength = AT_SMS_MAXLEN;
            memset(smsMsg->text, 0, AT_SMS_MAXLEN);
            memcpy(smsMsg->text, text, AT_SMS_MAXLEN);
            smsMsg->format = PARA_VALUE_3G_SMS_FORMAT_UNICODE;
            text += AT_SMS_MAXLEN;
            addMsgToFifoMsgQueue(&mgr2SmsMsgQueue, smsMsg, sizeof(SMS_MSG));
        }
        if(len > (item*AT_SMS_MAXLEN))
        {
            /* the remaining string */
            len = len - (item*AT_SMS_MAXLEN);
            smsMsg->smsLength = len;
            memset(smsMsg->text, 0, AT_SMS_MAXLEN);
            memcpy(smsMsg->text, text, len);
            smsMsg->format = PARA_VALUE_3G_SMS_FORMAT_UNICODE;
            addMsgToFifoMsgQueue(&mgr2SmsMsgQueue, smsMsg, sizeof(SMS_MSG));
        }
    }
    else
    {
        smsMsg->smsLength = len;
        memset(smsMsg->text, 0, AT_SMS_MAXLEN);
        memcpy(smsMsg->text, text, len);
        smsMsg->format = PARA_VALUE_3G_SMS_FORMAT_UNICODE;
        addMsgToFifoMsgQueue(&mgr2SmsMsgQueue, smsMsg, sizeof(SMS_MSG));
    }
}

void prompt_menulist(SMS_MSG *smsMsg)
{
    int32_t index;
    int32_t loop;
    int32_t len;
    char *pText1, *pText2, *tmp;

    pText1 = (char *)malloc(4096);
    pText2 = pText1 + 2048;
    if(pText1)
    {
        memset(pText1, 0, 2048);
        memset(pText2, 0, 2048);
        tmp = pText1;
        loop = sizeof(MenuList)/sizeof(MenuList[0]);
        len  = 0;

        for(index=0; index<loop; index++)
        {
            sprintf(tmp, "%s:%s\n", MenuList[index].id, MenuList[index].text);
            len += strlen(tmp);
            tmp = pText1 + len;
        }

        if(len < 2048)
        {
            len = Utf8ToUtf16(pText1, len, pText2, 2048);

            tmp = pText2 + 2;/* skip fffe */

            dongle_send_msg(tmp, len, smsMsg);
        }
        else
        {
            DONGLE_LOG(LOG_NOTICE, "Menu too long\n");
        }
        free(pText1);
    }
    else
    {
        printf("malloc memory fail!\n");
    }
}

void manage_recv_sms(Client_t *pcli)
{
    int32_t index;
    char *pText1;
    char *pText2;
    char *tmp;
    SMS_MSG *smsMsg;
    int32_t len;
    int32_t prompt = 0;

    if((pcli != NULL) && pcli->flag && smsMainEnabled)
    {
        pText1 = (char *)malloc(4096);
        pText2 = pText1 + 2048;
        if(pText1)
        {
            pcli->flag = 0;
            smsMsg = &pcli->sms;
            memset(pText1, 0, 4096);
            switch(pcli->Auth)
            {
                case Auth_Init:
                    pcli->Auth = Auth_WaitPassword;
                    if(smsMsg->format == PARA_VALUE_3G_SMS_FORMAT_ASCII)
                    {
                        if(!strcmp(smsMsg->text, SMS_PASSWORD ))
                        {
                            /* list the support command*/
                            prompt_menulist(smsMsg);
                            pcli->Auth = Auth_Normal;
                            gettimeofday(&pcli->stamp, NULL);
                        }
                        else
                        {
                            prompt = 1;
                        }
                    }
                    else
                    {
                        prompt = 1;
                    }

                    if(prompt)
                    {
                        /* prompt input passowrd */
                        sprintf(pText1, "请输入密码：\n");
                        len = Utf8ToUtf16(pText1, strlen(pText1), pText2, 2048);
                        tmp = pText2 + 2;/* skip fffe */
                        dongle_send_msg(tmp, len, smsMsg);
                    }
                    break;
                case Auth_WaitPassword:
                    if(smsMsg->format == PARA_VALUE_3G_SMS_FORMAT_ASCII)
                    {
                        if(!strcmp(smsMsg->text, smsKey))
                        {
                            /* list the support command*/
                            prompt_menulist(smsMsg);
                            pcli->Auth = Auth_Normal;
                            gettimeofday(&pcli->stamp, NULL);
                        }
                    }
                    break;
                case Auth_Normal:
                    gettimeofday(&pcli->stamp, NULL);
                    if(smsMsg->format == PARA_VALUE_3G_SMS_FORMAT_ASCII)
                    {
                        index = FindMenuItems(smsMsg);
                        if(index < 0)
                        {
                            prompt_menulist(smsMsg);
                        }
                        else
                        {
                            if(MenuList[index].handler != NULL)
                            {
                                tmp = MenuList[index].handler(smsMsg->text);
                                if(tmp != NULL)
                                {
                                    len = Utf8ToUtf16(tmp, strlen(tmp), pText2, 2048);
                                    if(len > 0)
                                    {
                                        tmp = pText2 + 2;/* skip fffe */
                                        if(index == 8)
                                        {
                                            smsMsg->header.msgId = MSG_ID_RESET;/* to reset the dongle */
                                        }
                                        dongle_send_msg(tmp, len, smsMsg);
                                    }
                                }
                            }                   
                        }
                    }
                    else
                    {
                        prompt_menulist(smsMsg);
                    }
                    break;
                case Auth_Timeout:
                    break;
                default:
                    break;
            }
        }
        free(pText1);
    }

    return;
}

void client_manage(void)
{
    struct timeval cur;
    unsigned int i;

    gettimeofday(&cur, NULL);

    for(i=0; i<sizeof(RemoteClients)/sizeof(RemoteClients[0]); i++)
    {
        if(strlen(RemoteClients[i].sms.callerId))
        {
            manage_recv_sms(&RemoteClients[i]);

            if((RemoteClients[i].Auth == Auth_Normal) && (cur.tv_sec - RemoteClients[i].stamp.tv_sec)>SESSION_TIMEOUT)
            {
                ReleaseClient(i);
            }
        }
    }
}

void handle_msg_from_smstask()
{
	int sms_count = getQueuedMsgsCount(&sms2MgrMsgQueue.pool);
	if( sms_count > 0 )
	{
		int i = 0;
		for ( ; i < sms_count; ++i )
		{
			void *buffer = NULL;
			uint32_t length = 0;
			uint32_t index;
			getMsgFromFifoMsgQueue(&sms2MgrMsgQueue, &buffer, &length);
			if( length != 0 )
			{
				MSG_HEADER *header = (MSG_HEADER *)buffer;
				switch( header->msgId )
				{
					case MSG_ID_SMS:
					{
						SMS_MSG *smsMsg = (SMS_MSG *)buffer;
	
						if( smsMsg->header.msgId == 1 )
						{
							DONGLE_LOG(LOG_NOTICE, "Get a sms from %s, length=%d \n", smsMsg->callerId, smsMsg->smsLength);
							reportSms(smsMsg);
	
							index = FindClient(smsMsg->callerId);
										
							if(index >= sizeof(RemoteClients)/sizeof(RemoteClients[0]))
							{
										
								index = FindFreeClient();
								if(index < sizeof(RemoteClients)/sizeof(RemoteClients[0]))
								{
									 RemoteClients[index].sms = *smsMsg;
									 RemoteClients[index].flag= 1;
								}
								else
								{
									 DONGLE_LOG(LOG_WARNING, "Client full!\n");
								}
							}
						    else
							{									   
								RemoteClients[index].sms = *smsMsg;
								RemoteClients[index].flag= 1;
							}
						}
									
						break;
					}
					case MSG_ID_SIM_STATE_RSP:
					{
						SIM_STATE *simState = (SIM_STATE *)buffer;
						reportSimState(sim_state_dst_id, sim_state_cmd_idx, simState);
						break;								
					}
					case MSG_ID_ALARM:
					{
						 SMS_ALARM *alarm = (SMS_ALARM *)buffer;
						 reportAlarm(alarm);
							 
						 break;
					}
					default:
						break;
				}
			}
		}
	}

}

static void* dongle_main(void *arg __attribute__((unused)))
{
    pthread_setname_np(pthread_self(), "3gdongle");

    initFifoMsgQueue(&mgr2SmsMsgQueue, "mgr2SmsMsgQueue", MGR2SMS_MSGQUEUE_SIZE, true, AT_RSP_MAXLEN);
    initFifoMsgQueue(&sms2MgrMsgQueue, "sms2MgrMsgQueue", MGR2SMS_MSGQUEUE_SIZE, true, AT_RSP_MAXLEN);
    
    if( !initckeckWan() )
    {
        DONGLE_LOG(LOG_CRIT, "can't create checkWan thread \n");    
    }
	
    char msg_buf[MAX_MSG_SIZE] = {0};
    int32_t tickTime = 0;
    while(1)
    {
        memset(msg_buf, 0, MAX_MSG_SIZE);
        MSGHEADER *msg_hdr = (MSGHEADER *)msg_buf;

        if( msgrcv(rx_queue_id, (void*)&msg_buf, MAX_MSG_SIZE, MSGQ_TYPE_SMS, IPC_NOWAIT) < 0 )
        {
            int err = errno;
            if( err <= 0 && err != EINTR )
            {
                DONGLE_LOG(LOG_WARNING, "msgrcvError %s\n", strerror(err));
            }
        }
        else
        {
            DONGLE_LOG(LOG_INFO, "received msg from 0x%X, len=%d \n", msg_hdr->srcID, msg_hdr->msgLength);
            debug_dump_buffer(msg_hdr->msgLength, msg_buf);
            tvl3gMsgHdlr(msg_hdr);
        }
		
        sleep(1);

		//every 5 second, send heartbeat to sysMonitor
        if ( tickTime >= 5 )
        {
			report3gHeartBeat(true);
            tickTime = 0;
        }
		
        tickTime++;
    }
    
    freeFifoMsgQueue(&mgr2SmsMsgQueue);
    freeFifoMsgQueue(&sms2MgrMsgQueue);

    pthread_exit((void*)0);
}

static void* dongle_main_quarantine(void *arg __attribute__((unused)))
{
    pthread_setname_np(pthread_self(), "3gdongle");

    initFifoMsgQueue(&mgr2SmsMsgQueue, "mgr2SmsMsgQueue", MGR2SMS_MSGQUEUE_SIZE, true, AT_RSP_MAXLEN);
    initFifoMsgQueue(&sms2MgrMsgQueue, "sms2MgrMsgQueue", MGR2SMS_MSGQUEUE_SIZE, true, AT_RSP_MAXLEN);
    initMutex();
    
    if( !initSmsTask() )
    {
        DONGLE_LOG(LOG_CRIT, "can't create smstask thread \n");
        smsTaskEnabled = false;
    }
    else
    {
        smsTaskEnabled = true;
    }
	
    initckeckWan();
    char msg_buf[MAX_MSG_SIZE] = {0};
    memset(RemoteClients, 0, sizeof(RemoteClients));
    int32_t tickTime = 0;
    while( ! stop_3g_thread )
    {
        memset(msg_buf, 0, MAX_MSG_SIZE);
        MSGHEADER *msg_hdr = (MSGHEADER *)msg_buf;

        if( msgrcv(rx_queue_id, (void*)&msg_buf, MAX_MSG_SIZE, MSGQ_TYPE_SMS, IPC_NOWAIT) < 0 )
        {
            int err = errno;
            if( err <= 0 && err != EINTR )
            {
                DONGLE_LOG(LOG_WARNING, "msgrcvError %s\n", strerror(err));
            }
        }
        else
        {
            DONGLE_LOG(LOG_INFO, "received msg from 0x%X, len=%d \n", msg_hdr->srcID, msg_hdr->msgLength);
            debug_dump_buffer(msg_hdr->msgLength, msg_buf);
            tvl3gMsgHdlr(msg_hdr);
        }

        client_manage();
        /* get msg from smstask */
        handle_msg_from_smstask();       
		
        sleep(1);
        if ( tickTime >= 5 )
        {
            if ( smsIsOk  )
                report3gHeartBeat(CheckTick() && GetCheckWanThreadIsOk());
            else
                report3gHeartBeat( GetCheckWanThreadIsOk() );
            tickTime = 0;
        }
        tickTime++;
    }
    
    freeFifoMsgQueue(&mgr2SmsMsgQueue);
    freeFifoMsgQueue(&sms2MgrMsgQueue);

    pthread_exit((void*)0);
}

void RollOverLog()
{ 
    int32_t tmp = 0;
    struct stat logStat;
    tmp = stat(dongleLogFile, &logStat);
    if ( tmp != -1 )
    {
        char name[128] = {0};
        sprintf(name, "%s.old", dongleLogFile);
        remove(name);
        rename(dongleLogFile, name);
    }
    log = fopen(dongleLogFile, "a");
    while((dup2(STDOUT_FILENO, STDERR_FILENO) == -1) && (errno== EINTR))
    {
    };
}


const char *shortname(const char *filename)
{ 
    return strrchr(filename, '/') != 0 ? strrchr(filename, '/')+1 : filename;
}


 void dongle_app_savelog(int32_t level, const char *filename, uint32_t line,  char *fmt, ...)
{
    va_list ap;
    time_t rawtime;
    struct tm p = { 0 };
   
    if (level > dongleLogLevel) 
	{
        return ;
    }
    lineNum++;
	if (log == NULL) 
	{
        log = fopen(dongleLogFile, "a");
        if ( log == NULL )
        {
            fprintf(stderr, "Open log_file:%s failed!!\n", dongleLogFile);
            return ;
        }
    }
    time(&rawtime);
    localtime_r(&rawtime, &p);
    


    fprintf(log, "%04d/%02d/%02d %02d:%02d:%02d %s[%d] %s %d ", (1900 + p.tm_year),
            (1 + p.tm_mon), p.tm_mday, p.tm_hour, p.tm_min, p.tm_sec, filename, line, LogLevelName[level],  lineNum);
//    printf("%04d/%02d/%02d %02d:%02d:%02d %s[%d] %s %d ", (1900 + p.tm_year),
//            (1 + p.tm_mon), p.tm_mday, p.tm_hour, p.tm_min, p.tm_sec, filename, line, LogLevelName[level-1], lineNum);

    va_start(ap, fmt);
    vfprintf(log, fmt, ap);
 //   vprintf(fmt, ap);
    va_end(ap);
    fflush(log);
    if ( lineNum >= 30000 )
    {
        fclose(log);
        RollOverLog();
        lineNum = 0;

    }    
    return ;
}
 void lockThread()
{
    pthread_mutex_lock(&mutexLog);
}

 void unlockThread()
{
    pthread_mutex_unlock(&mutexLog);
}


#ifdef DONGLE_THREAD

RESULT dongle_init()
{
    pthread_t thread;

    if( RC_OK != MOD_register(&mod3gInfo) )
    {
        printf("Can't register module with syscore\n");
        return RC_FAIL;
    }
    signal(SIGCHLD, SIG_IGN);
    pthread_create(&thread, NULL, dongle_main, 0);

    return RC_OK;
}

#else

int main(int argc, char *argv[])
{
    pthread_mutex_init(&mutexLog, NULL);
    void *arg = NULL;
    char *par1, *par2;
    if ( argc == 3 )
    {
        par1 = argv[1];
        par2 = argv[2];
        if( strcmp(par1, "-l") == 0 )
        {
            if ( atoi(par2) < LOG_EMERG || atoi(par2) > LOG_USE_GLOBAL_FILTER )
            {
                dongleLogLevel = LOG_USE_GLOBAL_FILTER;
            }
            else
            {
                dongleLogLevel = atoi(par2);
            }
        }

    }
	
    memset(smsKey, 0, 16);
    strcpy(smsKey, "1635");
    RollOverLog();
    DONGLE_LOG(LOG_NOTICE, "start init 3gdongle");
    dongle_msgqueue_init();
    dongle_main(arg);

    return 0;
}
#endif 
